package com.xcity.game.employee;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Employee.State;
import com.xcity.db.entity.Player;
import com.xcity.game.combat.attr.CombatAttribute;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.employee.config.EmployeeServiceConfigure;
import com.xcity.game.employee.config.impl.EmployeeQualityLevelUpConfigure;
import com.xcity.game.employee.config.impl.EmployeeQualityLevelUpConfigure.EmployeeWrapper;
import com.xcity.game.employee.config.impl.EmployeeQualityLevelUpConfigure.PlayerWrapper;
import com.xcity.game.employee.config.impl.EmployeeQualityLevelUpConfigure.QualityUpgradable;
import com.xcity.game.employee.config.impl.EmployeeRebornConfigure;
import com.xcity.game.employee.config.impl.EmployeeRecruitConfigure;
import com.xcity.game.employee.config.impl.EmployeeRecruitConfigure.ConfigurationDropItem;
import com.xcity.game.employee.config.impl.EmployeeRecruitConfigure.EmployeeRecruitResult;
import com.xcity.game.employee.config.impl.EmployeeRecruitConfigure.RecruitListener;
import com.xcity.game.employee.config.impl.EmployeeRecruitConfigure.Type;
import com.xcity.game.employee.config.impl.EmployeeStarLevelUpConfigure;
import com.xcity.game.employee.template.EmployeeBlessTemplate;
import com.xcity.game.employee.template.EmployeeQualityUpTemplate;
import com.xcity.game.employee.template.EmployeeStarUpTemplate;
import com.xcity.game.employee.template.EmployeeTemplate;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemEffect;
import com.xcity.game.item.ItemInfo;
import com.xcity.game.item.ItemService;
import com.xcity.game.item.ItemTemplate;
import com.xcity.game.player.PlayerUtils;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.msg.BatchItemsPush;
import com.xcity.pomelo.request.EmployeeBlessInfoRequest;
import com.xcity.pomelo.request.EmployeeBlessRequest;
import com.xcity.pomelo.request.EmployeeComboInfoRequest;
import com.xcity.pomelo.request.EmployeeFeedRequest;
import com.xcity.pomelo.request.EmployeeFireRequest;
import com.xcity.pomelo.request.EmployeeInfoRequest;
import com.xcity.pomelo.request.EmployeeLearnSkillRequest;
import com.xcity.pomelo.request.EmployeeLevelUpInfoRequest;
import com.xcity.pomelo.request.EmployeeLevelUpRequest;
import com.xcity.pomelo.request.EmployeeListRequest;
import com.xcity.pomelo.request.EmployeePieceComposeRequest;
import com.xcity.pomelo.request.EmployeeQualityLevelUpInfoRequest;
import com.xcity.pomelo.request.EmployeeQualityLevelUpRequest;
import com.xcity.pomelo.request.EmployeeRebornInfoRequest;
import com.xcity.pomelo.request.EmployeeRebornRequest;
import com.xcity.pomelo.request.EmployeeRecruitInfoRequest;
import com.xcity.pomelo.request.EmployeeRecruitRequest;
import com.xcity.pomelo.request.EmployeeStarLevelUpInfoRequest;
import com.xcity.pomelo.request.EmployeeStarLevelUpRequest;
import com.xcity.pomelo.request.EmployeeStateSwitchRequest;
import com.xcity.pomelo.request.EmployeeTrainRequest;
import com.xcity.pomelo.response.EmployeeBlessInfoResponse;
import com.xcity.pomelo.response.EmployeeBlessResponse;
import com.xcity.pomelo.response.EmployeeComboInfoResponse;
import com.xcity.pomelo.response.EmployeeInfoResponse;
import com.xcity.pomelo.response.EmployeeLevelUpInfoResponse;
import com.xcity.pomelo.response.EmployeeLevelUpResponse;
import com.xcity.pomelo.response.EmployeeListResponse;
import com.xcity.pomelo.response.EmployeeQualityUpInfoResponse;
import com.xcity.pomelo.response.EmployeeQualityUpResponse;
import com.xcity.pomelo.response.EmployeeRebornInfoResponse;
import com.xcity.pomelo.response.EmployeeRebornResponse;
import com.xcity.pomelo.response.EmployeeRecruitResponse;
import com.xcity.pomelo.response.EmployeeRecruiteInfoResponse;
import com.xcity.pomelo.response.EmployeeStarUpInfoResponse;
import com.xcity.pomelo.response.EmployeeStarUpResponse;
import com.xcity.pomelo.response.EmployeeStateSwitchResponse;
import com.xcity.pomelo.response.EmployeeTrainResponse;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.Response;
import com.xcity.util.ExpCalculator;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;

/**
 * 员工系统
 * @author yang.li
 *
 */
@OPHandler
public class EmployeeService implements Service, DayListener, EventListener {
	
	protected EmployeeServiceConfigure configure; // hold all configurations of employee service
	
	public static final Random RND = new Random();
	
	public static final Logger LOG = LoggerFactory.getLogger(EmployeeService.class);

	@Override
	public void startup() throws ServiceException {
		configure = new EmployeeServiceConfigure().configure();
		EmployeeUtils.initV2();
		App.getApp().getEventManager().register(this);
//		TimeUpdater.getInstance().addDayListener(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return getClass().getName();
	}
	
	public EmployeeServiceConfigure configure() {
		return configure;
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_RECRUIT_INFO)
	protected void requestRecruitInfo(Session session, EmployeeRecruitInfoRequest req){
		Player player = session.getClient();
		int lastDay = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_LAST_RECRUIT_DAY, 0);
		int today = TimeUpdater.getInstance().today();
		int stoneCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_RECRUIT_COUNT, 0);
		if(lastDay != today){
			resetLastRecruitDay(player, "RECRUITINFO");
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_LAST_RECRUIT_DAY, today);
		}
		player.send(new EmployeeRecruiteInfoResponse(req.getSerial(), player, configure.getRecruitConfigure().getShowGoldProduce(), configure.getRecruitConfigure().getShowStoneProduce(), configure.getRecruitConfigure().getShowBookProcue(), configure.getRecruitConfigure().tryGetNextFixDrop(stoneCount)));
	}
	/**
	 * 招聘员工
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_RECRUIT)
	protected void requestRecruit(Session session, EmployeeRecruitRequest req) {
//		EmployeeRecruitConfigure.Type type = EmployeeRecruitConfigure.Type.forCode(req.getType());
		byte type = req.getType();
		if (type < 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ILLEGAL_OPERATION));
			return;
		}
		Player player = session.getClient();
		if (player.getLevel() < GameStaticConfig.employeeRecruitOpenLvl) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_RECRUIT_LEVEL_LIMIT, GameStaticConfig.employeeRecruitOpenLvl)));
			return;
		}
		int capacity = PlayerUtils.getEmployeeCapcity(player);
		if (capacity > 0 && player.getEmployees().size() >= capacity) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_COUNT_EXCEED, capacity)));
			return;
		}
		int lastDay = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_LAST_RECRUIT_DAY, 0);
		int today = TimeUpdater.getInstance().today();
		if(lastDay != today){
			resetLastRecruitDay(player, "RECRUIT");
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_LAST_RECRUIT_DAY, today);
		}
		List<EmployeeRecruitResult> resultList = new ArrayList<EmployeeRecruitResult>();
		int curCount = 0;
		int todayFreeCount = -1;
		int todayRollCount = -1;
		int todayHalfCount = -1;
		int stoneFixDropNext = -1;
		int stoneHalf10 = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_FIRST_TEN, 0);
		if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_MONEY_ONE){
			//金币单抽(固定掉落>保底掉落>免费掉落>正常掉落)
			boolean needCost = false;//是否是花钱的
			todayRollCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_ONE_COUNT, 0);//剩余抽次
			int leftCount = GameStaticConfig.recruitMoneyCountLimit1 - todayRollCount;
			if(leftCount <= 0){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_COUNT));
				return;
			}
			//免费次数 扣金币
			todayFreeCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_FREE_COUNT, 0);
			int leftFreeCount = GameStaticConfig.recruitMoneyFreeCount - todayFreeCount;
			if(leftFreeCount <= 0){
				needCost = true;
			}
			if(needCost){//不是免费 扣钱先
				if(!player.costGold(GameStaticConfig.recruitCostMoneyOne, Cause.EMPLOYEE_RECRUIT)){//金币不足
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_MONEY));
					return;
				}
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, 0);
			EmployeeRecruitResult result = configure.getRecruitConfigure().tryFixedDropGroup(player, curCount + 1, type);
			if(result == null){
				if(curCount % 10 == 9){//保底产出			
					result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_BASE, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
				}else{
					if(needCost){//花钱的
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_ONE, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
					}else{//不花钱的					
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_FREE, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
					}
				}
				//发奖励
				RecruitListener listener = new RecruitListener();
				player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
				result.reputItemId(listener);
			}
			resultList.add(result);
			if(!needCost){//扣免费次数
				todayFreeCount++;
				player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_FREE_COUNT, todayFreeCount);
			}else{
				//扣抽次
				todayRollCount++;
				player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_ONE_COUNT, todayRollCount);
			}
			//增加统计
			curCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_MONEY_TEN){
			//金币十抽(固定掉落>保底掉落>正常掉落)
			todayRollCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_TEN_COUNT, 0);//剩余抽次
			int leftCount = GameStaticConfig.recruitMoneyCountLimit10 - todayRollCount;
			if(leftCount <= 0){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_COUNT));
				return;
			}
			if(!player.costGold(GameStaticConfig.recruitCostMoneyTen, Cause.EMPLOYEE_RECRUIT)){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_MONEY));
				return;
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, 0);
			List<ConfigurationDropItem> dropListBase = new ArrayList<ConfigurationDropItem>();
			List<ConfigurationDropItem> dropListTen = new ArrayList<ConfigurationDropItem>();
			for(int i = 0; i < 10; i++){
				EmployeeRecruitResult result = configure.getRecruitConfigure().tryFixedDropGroup(player, curCount + 1, type);
				if(result == null){//非固定掉落
					if(curCount % 10 == 9){
						//保底产出
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_BASE, player, configure, dropListBase, 1);
					}else{
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_TEN, player, configure, dropListTen, 1);
					}
					//发奖励
					RecruitListener listener = new RecruitListener();
					player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
					result.reputItemId(listener);
				}
				resultList.add(result);
				//增加统计
				curCount++;
			}
			//扣抽次
			todayRollCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_TEN_COUNT, todayRollCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_MONEY_HUNDRED){
			//金币百抽(固定掉落>保底掉落>正常掉落)
			todayRollCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_HUNDRED_COUNT, 0);//剩余抽次
			int leftCount = GameStaticConfig.recruitMoneyCountLimit100 - todayRollCount;
			if(leftCount <= 0){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_COUNT));
				return;
			}
			if(!player.costGold(GameStaticConfig.recruitCostMoneyHundred, Cause.EMPLOYEE_RECRUIT)){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_MONEY));
				return;
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, 0);
			List<ConfigurationDropItem> dropListBase = new ArrayList<ConfigurationDropItem>();
			List<ConfigurationDropItem> dropListHundred = new ArrayList<ConfigurationDropItem>();
			for(int i = 0; i < 100; i++){
				EmployeeRecruitResult result = configure.getRecruitConfigure().tryFixedDropGroup(player, curCount + 1, type);
				if(result == null){//非固定掉落
					if(curCount % 10 == 9){
						//保底产出
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_BASE, player, configure, dropListBase, 1);
					}else{
						result = configure.getRecruitConfigure().doRecruitSingle(Type.MONEY_HUNDRED, player, configure, dropListHundred, 1);
					}
					//发奖励
					RecruitListener listener = new RecruitListener();
					player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
					result.reputItemId(listener);
				}
				resultList.add(result);
				//增加统计
				curCount++;
			}
			//扣抽次
			todayRollCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_HUNDRED_COUNT, todayRollCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_STONE_ONE){
			//钻石单抽
			boolean needCost = false;//是否是花钱的
			//免费次数 扣钻石
			todayFreeCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_FREE_COUNT, 0);
			int leftFreeCount = GameStaticConfig.recruitStoneFreeCount - todayFreeCount;
			if(leftFreeCount <= 0){
				needCost = true;
			}
			todayHalfCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_HALF_COUNT, 0);
			if(needCost){//不是免费 扣钱先
				int costStone = GameStaticConfig.recruitCostStoneOne;
				if(todayHalfCount == 0){//今天第一次半价
					costStone = costStone * GameStaticConfig.recruitStoneDiscount / 10;
				}
				if(!player.costStone(costStone, Cause.EMPLOYEE_RECRUIT)){//钻石不足
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_STONE));
					return;
				}
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_RECRUIT_COUNT, 0);
			EmployeeRecruitResult result = configure.getRecruitConfigure().tryFixedDropGroup(player, curCount + 1, type);
			if(result == null){//非固定掉落
				if(curCount % 10 == 9){//保底产出			
					result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_BASE, player, configure, new ArrayList<ConfigurationDropItem>(), curCount);
				}else{
					if(needCost){//花钱的					
						result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_ONE, player, configure, new ArrayList<ConfigurationDropItem>(), curCount);
					}else{//不花钱的					
						result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_FREE, player, configure, new ArrayList<ConfigurationDropItem>(), curCount);
					}
				}
				//发奖励
				RecruitListener listener = new RecruitListener();
				player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
				result.reputItemId(listener);
			}
			resultList.add(result);
			if(!needCost){//扣免费次数
				todayFreeCount++;
				player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_FREE_COUNT, todayFreeCount);
			}else{
				if(todayHalfCount == 0){
					todayHalfCount = 1;
					player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_HALF_COUNT, todayHalfCount);
				}
			}
			//增加统计
			curCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
			stoneFixDropNext = configure.getRecruitConfigure().tryGetNextFixDrop(curCount);
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_STONE_TEN){
			//钻石十抽(固定掉落>保底掉落>正常掉落)
			int isSequent = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);
			int cost = GameStaticConfig.recruitCostStoneTen;
			if(req.getStoneTen() != 0 && isSequent == 1){
				cost = GameStaticConfig.recruitCostStoneTenSequent;
			}
			if(stoneHalf10 == 0){
				cost = cost >> 1;
				if(cost <= 0){
					cost = 1;
				}
			}
			if(!player.costStone(cost, Cause.EMPLOYEE_RECRUIT)){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_STONE));
				return;
			}
			if(stoneHalf10 == 0){
				stoneHalf10 = 1;
				player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_FIRST_TEN, 1);
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_STONE_RECRUIT_COUNT, 0);
			List<ConfigurationDropItem> dropListBase = new ArrayList<ConfigurationDropItem>();
			List<ConfigurationDropItem> dropListTen = new ArrayList<ConfigurationDropItem>();
			List<Integer> configCountList = configure.getRecruitConfigure().getCountLimitList();
			int configCountSize = configCountList.size();
			int currentCountIndex = 0;
			int lastCountIndex = 0;
			int goodLuckCount = 0;
			for(int i = 0; i < 10; i++){
				EmployeeRecruitResult result = configure.getRecruitConfigure().tryFixedDropGroup(player, curCount + 1, type);
				for(int j = currentCountIndex; j < configCountSize; j++){
					if(curCount >= configCountList.get(j)){
						currentCountIndex = j + 1;
					}else{
						break;
					}
				}
				if(lastCountIndex != currentCountIndex){
					lastCountIndex = currentCountIndex;
					dropListTen.clear();//当次数超越上次统计次数时清空dropList 重新计算droplist
				}
				if(result == null){//非固定掉落
					if(curCount % 10 == 9){
						//保底产出
						result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_BASE, player, configure, dropListBase, curCount);
					}else{
						if(goodLuckCount >= EmployeeRecruitConfigure.PROTECT_FROM_GOODLUCK_MAX_COUNT){
							//防脸红
							dropListTen.clear();
							result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_TEN_BADLUCK, player, configure, dropListTen, curCount);
						}else{
							result = configure.getRecruitConfigure().doRecruitSingle(Type.STONE_TEN, player, configure, dropListTen, curCount);
							if(result.itemId > EmployeeRecruitConfigure.PROTECT_FROM_GOODLUCK_ITEMID_BEGIN && result.itemId < EmployeeRecruitConfigure.PROTECT_FROM_GOODLUCK_ITEMID_END){
								goodLuckCount++;
							}
						}
					}
					//发奖励
					RecruitListener listener = new RecruitListener();
					player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
					result.reputItemId(listener);
				}
				resultList.add(result);
				//增加统计
				curCount++;
			}
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 1);//上一次是钻石十连
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_SENIOR){//高级招聘
			//高级招聘(保底掉落>正常掉落)
			//扣物品
			if(!player.getBag().removeItem(Type.SENIOR_RESUME.val, 1, Cause.EMPLOYEE_RECRUIT)){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_SENIOR_BOOK));
				return;
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_SENIOR_RESUME_RECRUIT_COUNT, 0);
			EmployeeRecruitResult result;
			if(curCount % 10 == 9){//保底产出			
				result = configure.getRecruitConfigure().doRecruitSingle(Type.SENIOR_RESUME_BASE, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
			}else{
				result = configure.getRecruitConfigure().doRecruitSingle(Type.SENIOR_RESUME, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
			}
			//发奖励
			RecruitListener listener = new RecruitListener();
			player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
			result.reputItemId(listener);
			resultList.add(result);
			//增加统计
			curCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_SENIOR_RESUME_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
		}else if(type == EmployeeRecruitConfigure.RECRUIT_TYPE_GENERAL){//普通招聘
			//普通招聘(保底掉落>正常掉落)
			//扣物品
			if(!player.getBag().removeItem(Type.GENERAL_RESUME.val, 1, Cause.EMPLOYEE_RECRUIT)){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_RECRUIT_NOT_ENOUGH_GENERAL_BOOK));
				return;
			}
			curCount = player.getPool().getInt(PlayerPool.PROPERTY_EMPLOYEE_GENERAL_RESUME_RECRUIT_COUNT, 0);
			EmployeeRecruitResult result;
			if(curCount % 10 == 9){//保底产出			
				result = configure.getRecruitConfigure().doRecruitSingle(Type.GENERAL_RESUME_BASE, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
			}else{
				result = configure.getRecruitConfigure().doRecruitSingle(Type.GENERAL_RESUME, player, configure, new ArrayList<ConfigurationDropItem>(), 1);
			}
			//发奖励
			RecruitListener listener = new RecruitListener();
			player.getBag().addItemWithoutException(result.itemId, result.itemCount, Cause.EMPLOYEE_RECRUIT, listener);
			result.reputItemId(listener);
			resultList.add(result);
			//增加统计
			curCount++;
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_GENERAL_RESUME_RECRUIT_COUNT, curCount);
			player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次不是钻石十连
		}
//		if (type == EmployeeRecruitConfigure.Type.STONE) {
//			if (!player.costStone(type.val, Cause.EMPLOYEE_RECRUIT)) {
//				session.send(new HintResponse(req.getSerial(), MessageConst.STONE_NOT_ENOUTH));
//				return;
//			}
//		} else {
//			int itemId = type.val;
//			if (!player.getBag().removeItem(itemId, req.getNum(), Cause.EMPLOYEE_RECRUIT)) {
//				ShopItemTemplate shopItem = App.getApp().getServiceManager().get(TemplateService.class).get(ShopItemTemplate.class, itemId);
//				if (shopItem != null) {
//					session.send(new BuyTipPush(player, shopItem));
//				}
//				ItemTemplate item = App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, itemId);
//				session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.ITEM_NOT_ENOUGH, item.getName())));
//				return;
//			}
//		}
//		Employee employee = configure.getRecruitConfigure().doRecruit(type, player, configure);
//		player.getEmployees().addEmployee(employee, false, Cause.EMPLOYEE_RECRUIT);
		session.send(new EmployeeRecruitResponse(req.getSerial(), type, resultList, curCount, todayFreeCount, todayRollCount, todayHalfCount, stoneFixDropNext, stoneHalf10));
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_RECRUIT_EMPLOYEE, player, type);
		LOG.info("[EMPLOYEE RECRUIT]ID[{}]TYPE[{}]COUNT[{}]FREE[{}]LIMIT[{}]HALF[{}]", player.getId(), type, curCount, todayFreeCount, todayRollCount, todayHalfCount);
//		session.send(new EmployeeListResponse(req.getSerial(), employee, player));
//		LOG.info("[EMPLOYEE RECRUIT]ID[{}]EMPLOYEE[{}]EID[{}]TYPE[{}]", player.getId(), employee.getTemplate().getId(), employee.getId(), type);
	}
	
	
	/**
	 * 获取员工列表
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_LIST)
	protected void requestList(Session session, EmployeeListRequest req) {
		Player player = session.getClient();
//		Collection<Employee> list = player.getEmployees().getEmployees();
//		if (req.getType() == EmployeeListRequest.FREE && !list.isEmpty()) {
//			int size = list.size();
//			List<Employee> dup = new ArrayList<Employee>(size);
//			for (Employee e : list) {
//				if (e.getState() == State.FREE) {
//					dup.add(e);
//				}
//			}
//			list = dup;
//		}
		
		List<Employee> employees = player.getEmployees().getSortedList();
		if (employees.size() == 0) {
			session.send(new EmployeeListResponse(req.getSerial(), player, configure.getTemplateConfigure().getPiecesMap()));
			return;
		}
		int maxPage = (employees.size() + EmployeeListRequest.COUNT_PER_PAGE - 1) / EmployeeListRequest.COUNT_PER_PAGE;
		if (req.page < 1) {
			req.page = 1;
		} else if (req.page > maxPage) {
			req.page = maxPage;
		}
		int fromIndex = (req.page - 1) * EmployeeListRequest.COUNT_PER_PAGE;
		int toIndex = fromIndex + EmployeeListRequest.COUNT_PER_PAGE;
		if (toIndex > employees.size()) toIndex = employees.size();
		List<Employee> list = employees.subList(fromIndex, toIndex);
		// 请求第一页时才发碎片信息
		Map<Integer, EmployeeTemplate> piecesMap = req.page == 1 ? configure.getTemplateConfigure().getPiecesMap() : null;
		session.send(new EmployeeListResponse(req.getSerial(), list, req.page, maxPage, player, piecesMap));
	}
	
	/**
	 * 请求某个员工信息
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_INFO)
	protected void requestInfo(Session session, EmployeeInfoRequest req) {
		Player player = session.getClient();
		Employee e = player.getEmployees().get(req.getId());
		if (e == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		session.send(new EmployeeInfoResponse(req.getSerial(), e));
	}
	
	/**
	 * 解雇员工
	 * @param session
	 * @param req
	 */
	@Deprecated
	@PomeloOP(PomeloRoute.EMPLOYEE_FIRE)
	protected void requestFire(Session session, EmployeeFireRequest req) {
//		Player player = session.getClient();
//		try {
//			Employee e = player.getEmployees().remove(req.getId());
//			new FireOperation(player, e, this).send();
//			session.send(new EmployeeFireResponse(req.getSerial(), e.getId()));
//			LOG.info("[EMPLOYEE FIRE]ID[{}]EMPLOYEE[{}]EID[{}]LVL[{}]", player.getId(), e.getTemplate().getId(), e.getId(), e.getLevel());
//		} catch (EmployeeException e) {
//			session.send(new HintResponse(req.getSerial(), e.getMessage()));
//		}
		session.send(new HintResponse(req.getSerial(), MessageConst.FUNC_NOT_OPEN));
	}
	
	/**
	 * 培训员工
	 * @param session
	 * @param req
	 * @see #requestEmployeeLevelUp(Session, EmployeeLevelUpRequest)
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_TRAIN)
	protected void requestTrain(Session session, EmployeeTrainRequest req) {
		Player player = session.getClient();
		try {
			Employee employee = requestAddExpForEmployee(player, req.getId(), req.getItemId(), req.getCount());
			session.send(new EmployeeTrainResponse(req.getSerial(), employee));
		} catch (EmployeeException e) {
			session.send(new HintResponse(req.getSerial(), e.getMessage()));
		}
	}
	
	/**
	 * 员工状态切换
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_STATE_SWITCH)
	protected void requestSwitchState(Session session, EmployeeStateSwitchRequest req) {
		Player player = session.getClient();
		Employee employee = player.getEmployees().get(req.getId());
		if (employee == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		State oldState = employee.getState();
		State toState = State.forCodeOfOldVersion(req.getState());
		if (oldState == toState) {
			session.send(new EmployeeStateSwitchResponse(req.getSerial(), employee));
			return;
		}
		if (toState == State.FREE) {
			State state = State.DEFENSE;
			if (oldState == state || !state.enable) {
				// 若该员工正防守在某建筑中，则需要先从建筑中移除
//				player.getBuildings().employeeRemoved(employee);
				player.getBuildings2().fireEmployeeRemoved(employee);
			}
			state = State.CAPTURE;
			if (oldState == state || !state.enable) {
				player.getConquests().fireEmployeeRemoved(employee);
			}
			state = State.IN_FORMATION;
			if (oldState == state || !state.enable) {
//				CombatUtils.removeFromFormation(employee);
				player.getFormations().remove(employee);
			}
			employee.setState(toState, true);
		}
		session.send(new EmployeeStateSwitchResponse(req.getSerial(), employee));
		LOG.info("[EMPLOYEE STATE SWITCH]ID[{}]EMPLOYEE[{}]EID[{}]TRY[{}]OLD[{}]NEW[{}]",
				player.getId(), employee.getTemplate().getId(), employee.getId(),
				toState, oldState, employee.getState());
	}
	
	/**
	 * 恢复员工精力
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_FEED)
	protected void requestFeed(Session session, EmployeeFeedRequest req) {
		session.send(new HintResponse(req.getSerial(), MessageConst.FUNC_NOT_OPEN));
//		Player player = session.getClient();
//		Employee employee = player.getEmployees().get(req.getId());
//		if (employee == null) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
//			return;
//		}
//		if (employee.getEnergy() >= employee.getMaxEnergy()) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_ENERGY_FULL));
//			return;
//		}
//		List<ItemTemplate> foods = configure.getCommonConfigure().getFoods();
//		for (int i = 0; i < foods.size(); i++) {
//			ItemTemplate food = foods.get(i);
//			if (player.getBag().removeItem(food.getId(), 1, Cause.EMPLOYEE_FEED)) {
//				int val = employee.getMaxEnergy() - employee.getEnergy();
//				employee.addEnergy(val, Cause.EMPLOYEE_FEED);
//				session.send(new EmployeeFeedResponse(req.getSerial(), employee));
//				return;
//			}
//		}
//		session.send(new Response(req.getSerial()));
//		session.send(new BuyTipPush(player, foods.get(0).getId()));
	}
	
	/**
	 * 学习技能
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_LEARN_SKILL)
	protected void requestLearnSkill(Session session, EmployeeLearnSkillRequest req) {
		session.send(new HintResponse(req.getSerial(), MessageConst.FUNC_NOT_OPEN));
		
//		Player player = session.getClient();
//		Employee e = player.getEmployees().get(req.getId());
//		if (e == null) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
//			return;
//		}
//		GameItem item = player.getBag().getItem(req.getItemId());
//		if (item == null || item.getTemplate().getEffect() != ItemEffect.EMPLOYEE_SKILL_BOOK) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.HAS_NO_EMPLOYEE_EXP_BOOK));
//			return;
//		}
//		ItemTemplate book = item.getTemplate();
//		SkillTemplate skillTemp = App.getApp().getServiceManager().get(TemplateService.class).get(SkillTemplate.class, book.getParameter(0));
//		if (skillTemp == null) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.SYSTEM_ERROR));
//			return;
//		}
//		if (player.getBag().removeItem(item.getId(), 1, Cause.EMPLOYEE_LEARN_SKILL) == null) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.HAS_NO_EMPLOYEE_EXP_BOOK));
//			return;
//		}
////			2个参数：①可获得的员工技能id  ②获得概率（万分比）
//		EmployeeSkill oldSkill = null, newSkill = null;
//		if (CommonUtils.randomInt(GameStaticConfig.defaultChanceBase) < book.getParameter(1)) {
//			newSkill = new EmployeeSkill(skillTemp);
//			oldSkill = e.addSkill(newSkill);
//		}
//		Response res = new EmployeeLearnSkillResponse(req.getSerial(), e, oldSkill, newSkill);
//		session.send(res);
	}
	
	/**
	 * 碎片合成员工
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_COMPOSE)
	protected void requestPieceCompose(Session session, EmployeePieceComposeRequest req) {
		Player player = session.getClient();
		int employeeMax = PlayerUtils.getEmployeeCapcity(player);
		if (employeeMax > 0 && player.getEmployees().size() >= employeeMax) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_COUNT_EXCEED, employeeMax)));
			return;
		}
		EmployeeTemplate template = configure.getTemplateConfigure().findTemplate(req.getId());
		if (template == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		int pieceId = template.getPieceId();
		int pieceCount = template.getPieceCount();
		if (pieceId <= 0 || pieceCount <= 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_CAN_NOT_COMPOSE_BY_PIECES));
			return;
		}
		if (!player.getBag().removeItem(pieceId, pieceCount, Cause.PIECE_COMPOSED)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_PIECES_NOT_ENOUGH));
			return;
		}
		Employee employee = new Employee(template, player.getEmployees(), configure);
		player.getEmployees().addEmployee(employee, true, Cause.PIECE_COMPOSED);
		session.send(new Response(req.getSerial()));
	}
	
	/**
	 * 员工（玩家）升品信息
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_QUALITY_LEVEL_UP_INFO)
	protected void requestQualityLevelUpInfo(Session session, EmployeeQualityLevelUpInfoRequest req) {
		Player player = session.getClient();
		QualityUpgradable wrapper;
		if (req.getId() == -1 || req.getId() == player.getId()) { // 玩家自己
			wrapper = new PlayerWrapper(player);
		} else {
			Employee employee = player.getEmployees().get(req.getId());
			if (employee == null) {
				session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
				return;
			}
			wrapper = new EmployeeWrapper(employee);
		}
		session.send(new EmployeeQualityUpInfoResponse(req.getSerial(), player, wrapper, this));
	}
	
	/**
	 * 员工（玩家）升品
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_QUALITY_LEVEL_UP)
	protected void requestQualityLevelUp(Session session, EmployeeQualityLevelUpRequest req) {
		Player player = session.getClient();
		QualityUpgradable wrapper;
		if (req.getId() == -1 || req.getId() == player.getId()) { // 玩家自己
			wrapper = new PlayerWrapper(player);
		} else {
			Employee employee = player.getEmployees().get(req.getId());
			if (employee == null) {
				session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
				return;
			}
//			if (player.getEmployees().hasTheSameKindTrainedEmployee(employee)) {
//				session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_TRAIN_THE_SAME_KIND, employee.getTemplate().getName())));
//				return;
//			}
			wrapper = new EmployeeWrapper(employee);
		}
		EmployeeQualityLevelUpConfigure configure = this.configure.getQualityLevelUpConfigure();
		EmployeeQualityUpTemplate template = configure.getNextLevelTemplate(wrapper);
		if (template == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.UNIT_QUALITY_LEVEL_MAXED));
			return;
		}
		if (wrapper.getLevel() < template.getLevelLimit()) {
			String message = MessageFormat.format(
							MessageConst.UNIT_QUALITY_LEVEL_UP_LIMITED,
							req.getId() == -1 ? MessageConst.UNIT_PLAYER : MessageConst.UNIT_EMPLOYEE,
							template.getLevelLimit());
			session.send(new HintResponse(req.getSerial(), message));
			return;
		}
		if (template.getGold() > 0 && !player.isGoldEnough(template.getGold())) {
			session.send(new HintResponse(req.getSerial(), MessageConst.GOLD_NOT_ENOUGH));
			return;
		}
		ItemInfo lack = player.getBag().removeItems(Cause.EMPLOYEE_QUALITY_LEVEL_UP, template.getWrappedItems());
		if (lack != null) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.ITEM_NOT_ENOUGH, lack.getTemplate().getName())));
			return;
		}
		player.costGold(template.getGold(), Cause.EMPLOYEE_QUALITY_LEVEL_UP);
		int oldQLvl = wrapper.getQualityLevel();
		wrapper.addQualityLevel(1, template, Cause.MANUAL);
		session.send(new EmployeeQualityUpResponse(req, player, wrapper, template, this));
		if (wrapper.getId() != player.getId()) {
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_EMPLOYEE_QUALITY_UP, player, wrapper.reference(), oldQLvl);
		}
	}
	
	/**
	 * 员工升星信息
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_STAR_LEVEL_UP_INFO)
	protected void requestEmployeeStarLevelUpInfo(Session session, EmployeeStarLevelUpInfoRequest req) {
		Player player = session.getClient();
		Employee employee = player.getEmployees().get(req.getId());
		if (employee == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		session.send(new EmployeeStarUpInfoResponse(req.getSerial(), player, employee, this));
	}
	
	/**
	 * 员工升星
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_STAR_LEVEL_UP)
	protected void requestEmployeeStarLevelUp(Session session, EmployeeStarLevelUpRequest req) {
		Player player = session.getClient();
		Employee employee = player.getEmployees().get(req.getId());
		if (employee == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
//		if (player.getEmployees().hasTheSameKindTrainedEmployee(employee)) {
//			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_TRAIN_THE_SAME_KIND, employee.getTemplate().getName())));
//			return;
//		}
		EmployeeStarLevelUpConfigure configure = this.configure.getStarLevelUpConfigure();
		EmployeeStarUpTemplate template = configure.getNextLevelTemplate(employee);
		if (template == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_STAR_LEVEL_MAXED));
			return;
		}
		// 检测现金是否充足
		if (template.getGold() > 0 && !player.isGoldEnough(template.getGold())) {
			session.send(new HintResponse(req.getSerial(), MessageConst.GOLD_NOT_ENOUGH));
			return;
		}
		// 检测物品
		int itemId = template.getItemId();
		int itemCount = template.getItemCount();
		if (itemId != 0 && itemCount > 0 && !player.getBag().hasEnough(itemId, itemCount)) {
			ItemTemplate item = App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, itemId);
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.ITEM_NOT_ENOUGH, item.getName())));
			return;
		}
		// 检测卡牌并扣除
		int[] cards = new int[] {
				employee.getTemplate().getId(), template.getMainCardCount(),
				template.getViceCardId(), template.getViceCardCount()
		};
		if (!player.getEmployees().batchRemove(employee, cards, Cause.EMPLOYEE_STAR_LEVEL_UP)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_CARDS_NOT_ENOUGH));
			return;
		}
		// 扣现金
		player.costGold(template.getGold(), Cause.EMPLOYEE_STAR_LEVEL_UP);
		// 扣物品
		player.getBag().removeItem(itemId, itemCount, Cause.EMPLOYEE_STAR_LEVEL_UP);
		int oldStar = employee.getStarLvl();
		employee.addStarLevel(1, template, Cause.MANUAL);
		session.send(new EmployeeStarUpResponse(req.getSerial(), player, employee, template, this));
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_EMPLOYEE_STAR_UP, player, employee, oldStar);
	}
	
	/**
	 * 员工升级信息
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_LVL_UP_INFO)
	protected void requestEmployeeLevelUpInfo(Session session, EmployeeLevelUpInfoRequest req) {
		Player player = session.getClient();
		Employee employee = player.getEmployees().get(req.getId());
		if (employee == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		session.send(new EmployeeLevelUpInfoResponse(req.getSerial(), player, employee, this));
	}
	
	/**
	 * 员工升级
	 * @param session
	 * @param req
	 */
	@PomeloOP(PomeloRoute.EMPLOYEE_LVL_UP)
	protected void requestEmployeeLevelUp(Session session, EmployeeLevelUpRequest req) {
		Player player = session.getClient();
		try {
			Employee employee = player.getEmployees().get(req.getId());
			if (employee == null) {
				throw new EmployeeException(MessageConst.EMPLOYEE_NOT_EXIST);
			}
			int oldLvl = employee.getLevel();
			requestAddExpForEmployee(player, employee, req.getItemId(), req.getCount());
			session.send(new EmployeeLevelUpResponse(req.getSerial(), player, employee, oldLvl, this));
		} catch (EmployeeException e) {
			session.send(new HintResponse(req.getSerial(), e.getMessage()));
		}
	}
	
	private static Employee requestAddExpForEmployee(Player player, long employeeId, int itemId, int itemCount) throws EmployeeException {
		return requestAddExpForEmployee(player, player.getEmployees().get(employeeId), itemId, itemCount);
	}
	
	private static Employee requestAddExpForEmployee(Player player, Employee e, int itemId, int itemCount) throws EmployeeException {
		if (itemCount <= 0) {
			throw new EmployeeException(MessageConst.ILLEGAL_OPERATION);
		}
		if (player.getLevel() < GameStaticConfig.employeeTrainOpenLvl) {
			throw new EmployeeException(MessageFormat.format(MessageConst.EMPLOYEE_TRAIN_LEVEL_LIMIT, GameStaticConfig.employeeTrainOpenLvl));
		}
		if (e == null) {
			throw new EmployeeException(MessageConst.EMPLOYEE_TRAIN_SRC_NOT_EXIST);
		}
//		if (player.getEmployees().hasTheSameKindTrainedEmployee(e)) {
//			throw new EmployeeException(MessageFormat.format(MessageConst.EMPLOYEE_TRAIN_THE_SAME_KIND, e.getTemplate().getName()));
//		}
		int topLvl = EmployeeUtils.getMaxLevel(e.getTemplate().getQuality());
		if (e.getLevel() >= topLvl) {
			throw new EmployeeException(MessageConst.EMPLOYEE_TRAIN_LEVEL_MAX);
		}
//		if (e.getLevel() >= player.getLevel()) {
//			throw new EmployeeException(MessageConst.EMPLOYEE_LEVEL_OVER_PLAYER);
//		}
		ItemTemplate itemTemplate = App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, itemId);
		if (itemTemplate == null || itemTemplate.getEffect() != ItemEffect.ADD_EMPLOYEE_EXP_IMMEDIATELY) {
			throw new EmployeeException(MessageConst.EMPLOYEE_TRAIN_HAS_NO_STUFF);
		}
		int expOfPerBook = itemTemplate.getParameter(0);
		int maxLvl = player.getLevel() + 1;
		if (maxLvl > topLvl) {
			maxLvl = topLvl;
		}
		int maxLvlNeedExp = EmployeeUtils.getNeedTotalExp(e.getTemplate().getQuality(), maxLvl);
		int maxCount;
		if (maxLvl < topLvl) {
			maxCount = (maxLvlNeedExp - 1/*保证员工等级不能超过玩家等级*/ - e.getExp()) / expOfPerBook;
		} else {
			maxCount = (maxLvlNeedExp - e.getExp() + expOfPerBook - 1/*保证员工能升到顶级*/) / expOfPerBook;
		}
		// 实际使用数量
		int c = maxCount < itemCount ? maxCount : itemCount;
		if (c < 1) {
			throw new EmployeeException(MessageConst.EMPLOYEE_LEVEL_OVER_PLAYER);
		}
		boolean succ = player.getBag().removeItem(itemId, c, Cause.EMPLOYEE_TRAIN);
		if (!succ) {
			throw new EmployeeException(MessageFormat.format(MessageConst.ITEM_NOT_ENOUGH, itemTemplate.getName()));
		}
		e.addExp(expOfPerBook * c, Cause.EMPLOYEE_TRAIN);
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_TRAIN_EMPLOYEE, player, e);
		LOG.info("[EMPLOYEE TRAIN]ID[{}]EMPLOYEE[{}]EID[{}]EXP[{}]LVL[{}]ITEM[{}]COUNT[{}]COUNTREQ[{}]",
				player.getId(), e.getTemplate().getId(), e.getId(), e.getExp(), e.getLevel(), itemId, c, itemCount);
		return e;
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_BLESS_INFO)
	protected void requestEmployeeBlessInfo(Session session, EmployeeBlessInfoRequest req){
		Player player = session.getClient();
		int type = req.getType();
		int[] currentExp = new int[]{0, 0, 0, 0};
		int[] currentMaxExp = new int[]{0, 0, 0, 0};
		int[] lvls = new int[]{0, 0, 0, 0};
		List<CombatAttribute[]> oldSlot2Atts = new ArrayList<CombatAttribute[]>(4);
		List<CombatAttribute[]> slot2Atts = new ArrayList<CombatAttribute[]>(4);
		if(type != 0){
			return;
		}else{
			long eid = req.getEid();
			Employee employee = player.getEmployees().get(eid);
			if (employee == null) {
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
				return;
			}
			if(employee.getBlessExps() == null){
				employee.setBlessExps(new int[]{0, 0, 0, 0});
			}
			if(employee.getBlessLvls() == null){
				employee.setBlessLvls(new int[]{1, 1, 1, 1});
			}
//			if(employee.getAttributes() == null){
//				employee.setAttributes(new float[CombatAttributeType.length()]);
//			}
			for(int i = 0; i < 4; i++){
				int blessId = employee.getTemplate().getBlessId()[i];
				lvls[i] = employee.getBlessLvls()[i];
				List<EmployeeBlessTemplate> tempList = configure.getBlessConfigure().getBlessId2TempList().get(blessId);
				CombatAttribute[] oldAtts = null;
				CombatAttribute[] atts = null;
				if(tempList != null){
					if(lvls[i] < tempList.size()){
						currentMaxExp[i] = tempList.get(lvls[i]).getNeedExp();
//						atts = tempList.get(lvls[i]).getAttributes();
						atts = tempList.get(lvls[i]).getTotalAtts();
					}
					if(lvls[i] > 0){
						oldAtts = tempList.get(lvls[i] - 1).getTotalAtts();
					}
				}
				slot2Atts.add(atts);
				oldSlot2Atts.add(oldAtts);
				ExpCalculator calc = configure.getBlessConfigure().getBlessId2calc().get(blessId);
				currentExp[i] = calc.getCurrentLevelExp(lvls[i], employee.getBlessExps()[i]);//employee.getBlessExps()[i];
			}
		}
		player.send(new EmployeeBlessInfoResponse(req.getSerial(), req.getEid(), lvls, currentExp, currentMaxExp, slot2Atts, oldSlot2Atts));
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_BLESS)
	protected void requestEmployeeBless(Session session, EmployeeBlessRequest req){
		Player player = session.getClient();
		int costItemId = req.getItemId();
		int slot = req.getSlot();
		if(slot < 0 || slot >= 4){
			player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_WRONG_SLOT));
			return;
		}
		int retCurLvl = 0;
		int retCurExp = 0;
		int retMaxExp = 0;
		CombatAttribute[] retNextAtt = null;
		CombatAttribute[] retCurrentAtt = null;
//		List<CombatAttribute[]> deltaAttList = new ArrayList<CombatAttribute[]>();
		if(req.getType() != 0){
			//TODO
			return;
		}else{
			Employee employee = player.getEmployees().get(req.getEid());
			if (employee == null) {
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
				return;
			}
			int blessId = employee.getTemplate().getBlessId()[slot];
			ExpCalculator blessCalc = configure.getBlessConfigure().getBlessId2calc().get(blessId);
			List<EmployeeBlessTemplate> lvl2temp = configure.getBlessConfigure().getBlessId2TempList().get(blessId);
			int addexp = 0;
			if(blessCalc == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_CANT_ADD_EXP));
				return;
			}
			int curExp = employee.getBlessExps()[slot];
			int curLvl = employee.getBlessLvls()[slot];
			if(employee.getLevel() <= curLvl){
				player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_BLESS_LVL_LIMIT));
				return;
			}
			int maxLevel = employee.getLevel();
			int tempMaxLvl = blessCalc.getMaxLevel();//模版的最大等级
			if(maxLevel > tempMaxLvl){
				maxLevel = tempMaxLvl;
			}
			int maxExp = blessCalc.getTotalExp(maxLevel);
			if(costItemId != 0){
				int itemCount = req.getCount();
				if(itemCount <= 0){
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_BLESS_NO_ITEM));
					return;
				}
				//TODO
				ItemTemplate itemTemp = App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, costItemId);
				if(itemTemp == null){
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_ERROR_ITEM));
					return;
				}
				if(itemTemp.getEffect() != ItemEffect.ADD_BLESS_EXP){
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_ERROR_ITEM));
					return;
				}
				addexp = itemTemp.getParameter(0) * itemCount;
				if(curExp + addexp > maxExp){
					boolean needReturn = true;
					for(int i = itemCount - 1; i > 0; i--){
						int addExp2 = itemTemp.getParameter(0) * i;
						if(curExp + addExp2 <= maxExp){
							itemCount = i + 1;
							addexp = itemTemp.getParameter(0) * itemCount;
							needReturn = false;
							break;
						}
					}
					if(needReturn){
						player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_BLESS_MAX_LEVEL));
						return;
					}
				}
				//扣物品
				if(!player.getBag().removeItem(itemTemp.getId(), 1 * itemCount, "BLESS_ADD")){
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_ENOUGH_ITEM));
					return;
				}
			}else{
				//一键
				List<ItemTemplate> list = configure.getCommonConfigure().getBlessExpBooks();//从小到大
				List<Integer> costItemCounts = new ArrayList<Integer>();//从大到小!
				int count0 = 0;
				for(int i = list.size() - 1; i > -1; i--){
					ItemTemplate itemTemp = list.get(i);
					int count = player.getBag().countOf(itemTemp.getId());
					int tempAddExp = itemTemp.getParameter(0);
					int tempResult = 0;
					int addCount = 0;
					for(int j = 0; j < count; j++){
						tempResult = addexp + tempAddExp;
						if(curExp + tempResult < maxExp){
							addexp = tempResult;
							addCount++;
						}else{
							break;
						}
					}
					costItemCounts.add(addCount);
					if(count == 0){
						count0++;
					}
				}
				if(count0 >= list.size()){
					player.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_ENOUGH_ITEM));
					return;
				}
				//再从小到大补用一次物品
				for(int i = 0, size = list.size(); i < size; i++){
					int costCount = costItemCounts.get(size - i - 1);
					ItemTemplate itemTemp = list.get(i);
					int haveCount = player.getBag().countOf(itemTemp.getId());
					if(haveCount > costCount){
						//补用一次
						int tempAddExp = itemTemp.getParameter(0);
						if(curExp + addexp < maxExp && curExp + addexp + tempAddExp >= maxExp){
							addexp = addexp + tempAddExp;
							costItemCounts.set(size - i - 1, costCount + 1);
							break;
						}
					}
				}
				
				//扣物品
				for(int i = 0, size = list.size(); i < size; i++){
					int cost = costItemCounts.get(size - i - 1);
					if(cost > 0){
						player.getBag().removeItem(list.get(i).getId(), cost, "BLESS_ADD");
					}
				}
			}
			//加经验
			employee.addBlessExp(addexp, slot, blessCalc, lvl2temp, "BLESS_ADD");
			int newLvl = employee.getBlessLvls()[slot];
			//改变的属性返回值
			if(slot > -1){
				retCurLvl = employee.getBlessLvls()[slot];
//				List<EmployeeBlessTemplate> lvl2temp = configure.getBlessConfigure().getBlessId2TempList().get(blessId);
				if(retCurLvl < lvl2temp.size()){
					retMaxExp = lvl2temp.get(retCurLvl).getNeedExp();
					retNextAtt = lvl2temp.get(retCurLvl).getTotalAtts();
				}
				if(retCurLvl > 0){
					retCurrentAtt = lvl2temp.get(retCurLvl - 1).getTotalAtts();
				}
				ExpCalculator calc = configure.getBlessConfigure().getBlessId2calc().get(blessId);
				retCurExp = calc.getCurrentLevelExp(retCurLvl, employee.getBlessExps()[slot]);//employee.getBlessExps()[i];
			}
//			if(newLvl > curLvl){
//				for(int i = curLvl; i < newLvl; i++){
//					deltaAttList.add(lvl2temp.get(i).getAttributes());
//				}
//			}
		}
		player.send(new EmployeeBlessResponse(req.getSerial(), req.getEid(), req.getSlot(), retCurExp, retCurLvl, retMaxExp, retCurrentAtt, retNextAtt, null/*deltaAttList*/));
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_COMBO_INFO)
	protected void requestEmployeeComboInfo(Session session, EmployeeComboInfoRequest req) {
		EmployeeTemplate template = configure.getTemplateConfigure().findTemplate(req.getId());
		if (template == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		Player player = session.getClient();
		session.send(new EmployeeComboInfoResponse(req.getSerial(), player, template));
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_REBORN_INFO)
	protected void requestRebornInfo(Session session, EmployeeRebornInfoRequest req) {
		Player player = session.getClient();
		Employee employee;
		if (req.getId() <= 0 || (employee = player.getEmployees().get(req.getId())) == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		session.send(new EmployeeRebornInfoResponse(req.getSerial(), employee, configure.getRebornConfigure()));
	}
	
	@PomeloOP(PomeloRoute.EMPLOYEE_REBORN)
	protected void requestReborn(Session session, EmployeeRebornRequest req) {
		Player player = session.getClient();
		Employee employee;
		if (req.getId() <= 0 || (employee = player.getEmployees().get(req.getId())) == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
			return;
		}
		if (!employee.isTrained()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_REBORN_FRESHER));
			return;
		}
		EmployeeRebornConfigure conf = configure.getRebornConfigure();
		int costStone = conf.getRebornStone(employee);
		if (costStone > 0 && !player.costStone(costStone, Cause.REBORN)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.STONE_NOT_ENOUTH));
			return;
		}
		List<ItemInfo> items = conf.getRebornReturns(employee);
		BatchItemsPush sync = new BatchItemsPush(items.size());
		for (int i = 0; i < items.size(); i++) {
			ItemInfo item = items.get(i);
			if (item.getId() == ItemService.goldDefault.getId()) { // 现金直接加
				player.addGold(item.getCount(), Cause.REBORN);
			} else if (item.getId() == ItemService.addSkillPointsDefault.getId()) { // 技能点直接加
				player.addSkillPoints(item.getCount(), Cause.REBORN);
			} else {
				player.getBag().addItemOrSendMail(item.getTemplate(), item.getCount(), Cause.REBORN);
			}
			sync.add(item.getTemplate(), item.getCount());
		}
		int exp = employee.getExp();
		int qualityLvl = employee.getQualityLvl();
		int starLvl = employee.getStarLvl();
		employee.reborn();
		session.send(new EmployeeRebornResponse(req.getSerial(), employee, (byte) 1));
		session.send(sync);
		LOG.info("[EMPLOYEE REBORN]ID[{}]EMPLOYEE[{}]EID[{}]EXP[{}]QUALITYLVL[{}]STARLVL[{}]COST[{}]",
				player.getId(), employee.getTemplate().getId(), employee.getId(),
				exp, qualityLvl, starLvl, costStone);
	}

	@Override
	public boolean dayChanged() {
//		Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
//		for (Player player : players) {
//			try {
//				reset(player, Cause.AUTO_RECOVER);
//			} catch (Exception e) {
//				LOG.error(e.getMessage(), e);
//			}
//		}
		return true;
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_PLAYER_LOGIN };
	}

	@Override
	public void handleEvent(Event event) {
//		reset(event.getParameter(), Cause.LOGIN_RECOVER);
		playerLogin(event.getParameter(0));
	}
	
	private void playerLogin(Player player) {
		EmployeeUtils.doSort(player.getEmployees().getSortedList());
	}
	
//	private void reset(Player player, String cause) {
//		int lastDay = player.getPool().getIntValue(PlayerPool.PROPERTY_LAST_RECOVER_EMPLOYEE_ATTR_DAY);
//		if (lastDay != 0 && lastDay < TimeUpdater.getInstance().today()) {
//			player.poolSet(PlayerPool.PROPERTY_LAST_RECOVER_EMPLOYEE_ATTR_DAY, TimeUpdater.getInstance().today());
//			Collection<Employee> employees = player.getEmployees().getEmployees();
//			for (Employee e : employees) {
//				int val = e.getMaxEnergy() - e.getEnergy();
//				e.addEnergy(val, cause);
//			}
//		}
//	}
	
	private void resetLastRecruitDay(Player player, String cause){
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_FREE_COUNT, 0);//钻石免费次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_FREE_COUNT, 0);//金币免费次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_HALF_COUNT, 0);//钻石半价次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_ONE_COUNT, 0);//金币抽1次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_TEN_COUNT, 0);//金币抽10次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_MONEY_HUNDRED_COUNT, 0);//金币抽100次数
		player.getPool().put(PlayerPool.PROPERTY_EMPLOYEE_STONE_TEN_SEQUENT, 0);//上一次是否是钻石连续10次
		LOG.info("[EMPLOYEE RECRUIT RESET]ID[{}]CAUSE[{}]", player.getId(), cause);
	}

}
